package com.bolt.support.query.nativequery.parall;


import com.bolt.common.utils.SpringContextUtil;
import com.bolt.support.query.toolkit.JPAUtil;
import com.bolt.support.spring.jpa.transform.ConfigSqlTransformers;
import com.bolt.support.sqlconfig.base.SqlStatement;
import com.bolt.support.sqlconfig.base.SqlText;
import com.bolt.support.sqlconfig.builder.SqlTemplateFactory;
import org.hibernate.Session;
import org.hibernate.query.internal.NativeQueryImpl;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.Properties;
import java.util.concurrent.Callable;

public class ParallelQueryExecutor implements Callable<ParallelQueryResult> {

    private final EntityManager entityManager;

    private final SqlTemplateFactory sqlTemplateFactory;

    private final ParallelQuery parallelQuery;


    public ParallelQueryExecutor(EntityManager entityManager, SqlTemplateFactory sqlTemplateFactory, ParallelQuery parallelQuery) {
        this.entityManager = entityManager;
        this.sqlTemplateFactory = sqlTemplateFactory;
        this.parallelQuery = parallelQuery;

    }

    @Override
    public ParallelQueryResult call() throws Exception {
        ParallelQueryResult result = new ParallelQueryResult();
        Session session;
        try {
            JpaTransactionManager jpaTransactionManager = SpringContextUtil.getBean(JpaTransactionManager.class);
            DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
            transactionDefinition.setReadOnly(true);
            TransactionStatus transactionStatus = jpaTransactionManager.getTransaction(transactionDefinition);
            session = entityManager.unwrap(Session.class);
            session.setDefaultReadOnly(true);
            SqlStatement sqlStatement = sqlTemplateFactory.find(parallelQuery.getSqlId());
            SqlText sqlText = sqlStatement.getSqlText(parallelQuery.getParameterObject());
            Query query = entityManager.createNativeQuery(sqlText.getSql());
            Properties properties = sqlText.getParameterValues();
            JPAUtil.setParameter(query, properties);
            NativeQueryImpl nativeQuery = query.unwrap(NativeQueryImpl.class);
            nativeQuery.setResultTransformer(ConfigSqlTransformers.aliasToBean(parallelQuery.getReturnClass(), this.sqlTemplateFactory.getConfiguration()));
            result.setReturnClass(parallelQuery.getReturnClass());
            result.setRows(nativeQuery.getResultList());
            jpaTransactionManager.commit(transactionStatus);
        } catch (Exception ex) {
            result.setSuccess(false);
            result.setMessage(ex.getMessage());
        }
        return result;
    }


}